<template>
  <panel :title="`内存：${name}`">
    <div>
      <div v-if="current" class="content">
        <div v-if="current.metaspace" class="text-center">
          <p class="font-bold metaspace" v-text="'初始空间'" />
          <p v-text="prettyBytes(current.metaspace)" />
        </div>
        <div class="text-center">
          <p class="font-bold used" v-text="'已用'" />
          <p v-text="prettyBytes(current.used)" />
        </div>
        <div class="text-center">
          <p class="font-bold current" v-text="'当前可用'" />
          <p v-text="prettyBytes(current.committed)" />
        </div>
        <div v-if="current.max >= 0" class="text-center">
          <p class="font-bold" v-text="'最大'" />
          <p v-text="prettyBytes(current.max)" />
        </div>
      </div>

      <mem-chart v-if="chartData.length > 0" :data="chartData" />
    </div>
  </panel>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
import prettyBytes from 'pretty-bytes';
import panel from './panel.vue';
import api from "@/http/api";
import MemChart from './mem-chart.vue';

const props = defineProps({
  type: String
});

const current = ref(null);
const chartData = ref([]);
const tempData = ref([]);

const name = computed(() => {
  switch (props.type) {
    case 'heap':
      return 'Heap';
    case 'nonheap':
      return 'Non heap';
    default:
      return props.type;
  }
});

const fetchMetrics = async() => {
  const responseMax = api.get(`/actuator/metrics/jvm.memory.max?tag=area:${props.type}&tag=area:${props.type}`);
  const responseUsed = api.get(`/actuator/metrics/jvm.memory.used?tag=area:${props.type}&tag=area:${props.type}`);
  const hasMetaspace = (await responseUsed).data.availableTags.some(
    (tag) => tag.tag === 'id' && tag.values.includes('Metaspace'),
  );
  const responseMetaspace =
    props.type === 'nonheap' && hasMetaspace
      ? api.get(`/actuator/metrics/jvm.memory.used?tag=area:${props.type}&tag=area:${props.type}&tag=id:Metaspace`)
      : null;
  const responseCommitted = api.get(`/actuator/metrics/jvm.memory.committed?tag=area:${props.type}&tag=area:${props.type}`)
  const data = {
    max: (await responseMax).data.measurements[0].value,
    used: (await responseUsed).data.measurements[0].value,
    metaspace: responseMetaspace
      ? (await responseMetaspace).data.measurements[0].value
      : null,
    committed: (await responseCommitted).data.measurements[0].value,
  };

  const date = new Date();
  const timestamp = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`
  tempData.value.push({...data, timestamp: timestamp});
  if (chartData.value.length <= 2 || tempData.value.length >= 5) {
    chartData.value.push(...tempData.value);
    current.value = tempData.value[tempData.value.length - 1];
    tempData.value = [];
  }
};

const shutdown = ref(false);
const loopWithDelay = async(taskFn, interval = 1000) => {
  while (!shutdown.value) {
    await taskFn();
    await new Promise(res => setTimeout(res, interval));
  }
}

onMounted(() => {
  loopWithDelay(fetchMetrics);
});

onUnmounted(() => {
  shutdown.value = true;
});
</script>

<style scoped>
.content {
  display: flex;
  flex-direction: row;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  justify-content: space-between;
  .text-center {
    text-align: center;
    flex-grow: 1;
  }
  .font-bold {
    margin-bottom: 5px;
  }
  .used::before {
    background-color: #65A5D9;
    content: "";
    width: .75em;
    height: .75em;
    display: inline-block;
    margin-right: .25em;
  }
  .current::before {
    background-color: #FFE6A1;
    content: "";
    width: .75em;
    height: .75em;
    display: inline-block;
    margin-right: .25em;
  }
  .metaspace::before {
    background-color: #68DCB7;
    content: "";
    width: .75em;
    height: .75em;
    display: inline-block;
    margin-right: .25em;
  }
}
</style>